home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianButtons.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  31KB  |  1,250 lines

  1. /* ScianButtons.c:    John R. Murray, 3-30-90
  2.         creates and deals with button objects
  3. */
  4. #include "Scian.h"
  5. #include "ScianTypes.h"
  6. #include "ScianColors.h"
  7. #include "ScianIDs.h"
  8. #include "ScianMethods.h"
  9. #include "ScianLists.h"
  10. #include "ScianErrors.h"
  11. #include "ScianIcons.h"
  12. #include "ScianArrays.h"
  13. #include "ScianButtons.h"
  14. #include "ScianWindows.h"
  15. #include "ScianObjWindows.h"
  16. #include "ScianScripts.h"
  17. #include "ScianControls.h"
  18. #include "ScianEvents.h"
  19. #include "ScianFontSystem.h"
  20. #include "ScianStyle.h"
  21. #include "ScianDraw.h"
  22. #include "ScianTextBoxes.h"
  23. #include "ScianObjFunctions.h"
  24. #include "ScianSnap.h"
  25.  
  26. /* globals */
  27. ObjPtr    buttonClass;            /* class of buttons */
  28. ObjPtr    iconButtonClass;        /* class of icon buttons */
  29. ObjPtr    iconLabeledButtonClass;        /* class of labeled icon buttons */
  30. ObjPtr    radioButtonClass;        /* class of radio buttons */
  31. ObjPtr    oldRadioButtonClass;        /* class of radio buttons */
  32. ObjPtr    checkBoxClass;            /* class of check boxes */
  33. ObjPtr    radioGroupClass;        /* class of '90.. er, um.. */
  34.  
  35.  
  36. Bool inhibitSaveForUndo = false;
  37.  
  38. /* temporary defs to get something going */
  39.  
  40. /* none */
  41.  
  42. /* local constants */
  43. #define BUTTONDEPTH    4    /* button "height"=width (pixels) of border) */
  44. #define LABELFONTFUDGE    1    /* fudge strings up (or <0 = down) to center */
  45. #define RADIOSPACER    ((int) BUTTONFONTSIZE)
  46.                 /* distance in pixels from button to text */
  47.  
  48. /* values of object variables */
  49. #define MARKERX        0    /* value of var MARKERTYPE for mark = 'X' */
  50. #define MARKERCHECK    1    /* value of var MARKERTYPE for mark = check */
  51. #define MARKERBLOT    2    /* value of var MARKERTYPE for mark = dot */
  52. #define MARKERSPLAT    3    /* value of var MARKERTYPE for mark = splat */
  53.  
  54. static ObjPtr DrawButtonObj(theButton, theButtonOwner)
  55. ObjPtr    theButton, theButtonOwner;
  56. {
  57.  
  58. #ifdef GRAPHICS
  59.     int left, right, bottom, top;
  60.     int        depth;
  61.     Bool    hilight, active;
  62.     ObjPtr    theLabel;
  63.     char    *label;
  64.     ObjPtr    theColor;
  65.     int        color;
  66.  
  67.     if (!Get2DIntBounds(theButton, &left, &right, &bottom, &top))
  68.     {
  69.     return NULLOBJ;
  70.     }
  71.  
  72.     if (IsDrawingRestricted(left, right, bottom, top))
  73.     {
  74.     return ObjFalse;
  75.     }
  76.  
  77.     hilight = GetPredicate(theButton, HIGHLIGHTED);
  78.     active = GetPredicate(theButton, ACTIVATED);
  79.  
  80.     theLabel = GetVar(theButton, NAME);
  81.     if (theLabel)
  82.     {
  83.     label = GetString(theLabel);
  84.     }
  85.     else
  86.     {
  87.     label = (char *) NIL;
  88.     }
  89.  
  90.     theColor = GetVar(theButton, COLOR);
  91.     if (!theColor)
  92.     {
  93.     color = UIBACKGROUND;
  94.     }
  95.     else
  96.     {
  97.     color = GetPredicate(theButton, VALUE) ? GetInt(theColor) : UIBACKGROUND;
  98.     }
  99.  
  100.     if (!active)
  101.     {
  102.     BeginTranslucent();
  103.     DrawRaisedRect(left, right, bottom, top, hilight ? UIHIBACKGROUND : color);
  104.     EndTranslucent();
  105.     }
  106.     else
  107.     {
  108.     DrawRaisedRect(left, right, bottom, top, hilight ? UIHIBACKGROUND : color);
  109.     }
  110.  
  111.     if (label)
  112.     {
  113.     if (active)
  114.         SetUIColor(UITEXT);
  115.     else
  116.         SetUIColor(UIGREYTEXT);
  117.  
  118.     SetUIFont(BUTTONFONT);
  119.     DrawAString(CENTERALIGN, (left + right) / 2,
  120.            (top+bottom)/2 + LABELFONTFUDGE - ((int) BUTTONFONTSIZE/2),
  121.            label);
  122.     }
  123.     return ObjTrue;
  124. #endif /* GRAPHICS */
  125. }
  126.  
  127. ObjPtr    NewIconButton(left, right, bottom, top, icon, color, name, style)
  128. int    left, right, bottom, top;
  129. int    icon, color;
  130. char *name;
  131. int style;
  132. /*Makes a new icon button with bounds left, right, bottom, top,
  133.    with icon icon, and color color when on (otherwise drawn in UITEXT) */
  134. {
  135.     ObjPtr    retVal;
  136.     ObjPtr    iconPtr;
  137.     ObjPtr    hilightPtr;
  138.  
  139.  
  140.     retVal = NewObject(iconButtonClass, 0);
  141.     iconPtr = NewInt(icon);
  142.     SetVar(retVal, WHICHICON, iconPtr);
  143.     Set2DIntBounds(retVal, left, right, bottom, top);
  144.     hilightPtr = ObjFalse;
  145.     SetVar(retVal, HIGHLIGHTED, hilightPtr);
  146.     SetVar(retVal, VALUE, NewInt(0));
  147.     SetVar(retVal, COLOR, NewInt(color));
  148.     SetVar(retVal, ACTIVATED, ObjTrue);
  149.     if (style != BS_PLAIN && style != BS_PITTED)
  150.     {
  151.     ReportError("NewIconButton", "Illegal button style");
  152.     SetVar(retVal, STYLE, NewInt(BS_PLAIN));
  153.     }
  154.     else
  155.     {
  156.     SetVar(retVal, STYLE, NewInt(style));
  157.     }
  158.     if (name)
  159.     {
  160.     SetVar(retVal, NAME, NewString(name));
  161.     }
  162.     return retVal;
  163. }
  164.  
  165. /* DRAW method for icon buttons */
  166.  
  167. ObjPtr    DrawIconButtonObj(theButton, theButtonOwner)
  168. ObjPtr    theButton, theButtonOwner;
  169. {
  170.  
  171. #ifdef GRAPHICS
  172.     int left, right, bottom, top;
  173.     int        depth;
  174.     Bool    hilight, active;
  175.     ObjPtr    theIcon;
  176.     int        label;
  177.     ObjPtr    boundsArray;
  178.     real    bounds[4];
  179.     char    buttonLabel[128];
  180.     int        value;
  181.     ObjPtr    theColor;
  182.     int        color;
  183.     int        style;
  184.     FuncTyp    extraDraw;
  185.     int        diFlags;
  186.  
  187.     if (!Get2DIntBounds(theButton, &left, &right, &bottom, &top))
  188.     {
  189.     return NULLOBJ;
  190.     }
  191.  
  192.     if (IsDrawingRestricted(left, right, bottom, top))
  193.     {
  194.     return ObjFalse;
  195.     }
  196.  
  197.     hilight = GetPredicate(theButton, HIGHLIGHTED);
  198.     active = GetPredicate(theButton, ACTIVATED);
  199.     value = GetPredicate(theButton, VALUE);
  200.     style = GetInt(GetIntVar("DrawIconButtonObj", theButton, STYLE));
  201.  
  202.     color = UIGREEN;
  203.     diFlags = active ? DI_DRAWFORE | DI_DRAWBACK | DI_SMALLTEXT
  204.              : DI_DRAWFORE | DI_DRAWBACK | DI_SMALLTEXT | DI_GREY;
  205.     if (value)
  206.     {
  207.     if (GetVar(theButton, COLOR))
  208.     {
  209.         color = GetInt(GetIntVar("DrawIconButtonObj" ,theButton, COLOR));
  210.     }
  211.     /* if no COLOR, color remains UIGREEN */
  212.     }
  213.     else if (hilight)
  214.     {
  215.     color = UIHIBACKGROUND;
  216.     }
  217.     else
  218.     {
  219.     switch(style)
  220.     {
  221.         case BS_PLAIN:
  222.         color = UIBACKGROUND;
  223.         break;
  224.         case BS_PITTED:
  225.         color = UIICONBACK;
  226.         break;
  227.         default:
  228.         ReportError("DrawIconButtonObj", "Illegal STYLE");
  229.     }
  230.     }
  231.  
  232.     if (style == BS_PLAIN)
  233.     {
  234.     if (!active) BeginTranslucent();
  235.     DrawRaisedRect(left, right, bottom, top,
  236.         hilight ? UIHIBACKGROUND : UIBACKGROUND);
  237.     if (!active) EndTranslucent();
  238.     }
  239.     DrawIcon((left + right) / 2, (top + bottom) / 2,
  240.     GetInt(GetIntVar("DrawIconButtonObj", theButton, WHICHICON)),
  241.     (char *) NIL, (char *) NIL, color, diFlags);
  242.  
  243.     if (active)
  244.     {
  245.     extraDraw = GetMethod(theButton, ICONEXTRADRAW);
  246.     if (extraDraw)
  247.     {
  248.         (* extraDraw) (theButton, (int) ((left + right) / 2), (int) ((top + bottom) / 2));
  249.     }
  250.     }
  251.  
  252.     return ObjTrue;
  253. #endif /* GRAPHICS */
  254. }
  255.  
  256. ObjPtr    NewIconLabeledButton(left, right, bottom, top, icon, color, name, style)
  257. int    left, right, bottom, top;
  258. int    icon, color;
  259. char *name;
  260. int style;
  261. /*Makes a new icon button with bounds left, right, bottom, top,
  262.    with icon icon, color color when on (otherwise drawn in UITEXT)
  263.    and label name (name is also the name of the object) */
  264. {
  265.     ObjPtr    retVal;
  266.     ObjPtr    iconPtr, hilightPtr;
  267.  
  268.     retVal = NewObject(iconLabeledButtonClass, 0);
  269.     Set2DIntBounds(retVal, left, right, bottom, top);
  270.     iconPtr = NewInt(icon);
  271.     SetVar(retVal, WHICHICON, iconPtr);
  272.     hilightPtr = ObjFalse;
  273.     SetVar(retVal, HIGHLIGHTED, hilightPtr);
  274.     SetVar(retVal, VALUE, NewInt(0));
  275.     SetVar(retVal, ACTIVATED, ObjTrue);
  276.     SetVar(retVal, COLOR, NewInt(color));
  277.     if (style != BS_PLAIN && style != BS_PITTED)
  278.     {
  279.     ReportError("NewIconLabelledButton", "Illegal button style");
  280.     SetVar(retVal, STYLE, NewInt(BS_PLAIN));
  281.     }
  282.     else
  283.     {
  284.     SetVar(retVal, STYLE, NewInt(style));
  285.     }
  286.     if (name)
  287.     {
  288.     SetVar(retVal, NAME, NewString(name));
  289.     SetVar(retVal, LABEL, NewString(name));
  290.     }
  291.     else
  292.     {
  293.     SetVar(retVal, LABEL, NewString(""));
  294.     }
  295.     return retVal;
  296. }
  297.  
  298. ObjPtr    DrawIconLabeledButtonObj(theButton, theButtonOwner)
  299. ObjPtr    theButton, theButtonOwner;
  300. {
  301.  
  302. #ifdef GRAPHICS
  303.     int left, right, bottom, top;
  304.     int        depth;
  305.     Bool    hilight, active;
  306.     int        icon;
  307.     int        offset;
  308.     char    *label;
  309.     char    buttonLabel[128];
  310.     int        value;
  311.     ObjPtr    theColor;
  312.     int        color;
  313.     int        style;
  314.     FuncTyp    extraDraw;
  315.     int        diFlags;
  316.  
  317.     if (!Get2DIntBounds(theButton, &left, &right, &bottom, &top))
  318.     {
  319.         return NULLOBJ;
  320.     }
  321.  
  322.     if (IsDrawingRestricted(left, right, bottom, top))
  323.     {
  324.     return ObjFalse;
  325.     }
  326.  
  327.     hilight = GetPredicate(theButton, HIGHLIGHTED);
  328.     value = GetPredicate(theButton, VALUE);
  329.     active = GetPredicate(theButton, ACTIVATED);
  330.     style = GetInt(GetIntVar("DrawIconLabeledButtonObj", theButton, STYLE));
  331.  
  332.     if (GetVar(theButton, COLOR))
  333.     {
  334.     color = GetInt(GetIntVar("DrawIconLabeledButtonObj" ,theButton, COLOR));
  335.     }
  336.     else
  337.     {
  338.     color = UIGREEN;
  339.     }
  340.  
  341.     if (GetVar(theButton, WHICHICON))
  342.     {
  343.     icon = GetInt(GetIntVar("DrawIconLabeledButtonObj",theButton, WHICHICON));
  344.     }
  345.     else
  346.     {
  347.     icon = ICONQUESTION;
  348.     }
  349.  
  350.     if (GetVar(theButton, LABEL))
  351.     {
  352.     label = GetString(GetStringVar("DrawIconLabeledButtonObj",theButton, LABEL));
  353.     offset = ICONTEXTOFFSET / 2;
  354.     }
  355.     else
  356.     {
  357.     label = (char *) NIL;
  358.     offset = 0;
  359.     }
  360.  
  361.     color = UIGREEN;
  362.     if (value)
  363.     {
  364.     if (GetVar(theButton, COLOR))
  365.     {
  366.         color = GetInt(GetIntVar("DrawIconButtonObj" ,theButton, COLOR));
  367.     }
  368.     /* if no COLOR, color remains UIGREEN */
  369.     }
  370.     else if (hilight)
  371.     {
  372.     color = UIHIBACKGROUND;
  373.     }
  374.     else
  375.     {
  376.     switch(style)
  377.     {
  378.         case BS_PLAIN:
  379.         color = UIBACKGROUND;
  380.         break;
  381.         case BS_PITTED:
  382.         color = UIICONBACK;
  383.         break;
  384.         default:
  385.         ReportError("DrawIconButtonObj", "Illegal STYLE");
  386.     }
  387.     }
  388.  
  389.     diFlags = active ? DI_DRAWFORE | DI_DRAWBACK
  390.              : DI_DRAWFORE | DI_DRAWBACK | DI_GREY;
  391.     switch (style)
  392.     {
  393.     case BS_PLAIN:
  394.         diFlags = diFlags | DI_SMALLTEXT;
  395.         break;
  396.     case BS_PITTED:
  397.         break;
  398.     default:
  399.         ReportError("DrawIconLabelledButtonObj", "Illegal STYLE");
  400.     }
  401.  
  402.     if (style == BS_PLAIN)
  403.     {
  404.     if (!active) BeginTranslucent();
  405.     DrawRaisedRect(left, right, bottom, top,
  406.         hilight ? UIHIBACKGROUND : UIBACKGROUND);
  407.     if (!active) EndTranslucent();
  408.     }
  409.     DrawIcon((left + right) / 2, (top + bottom) / 2 + offset,
  410.     icon, label, (char *) NIL, color, diFlags);
  411.  
  412.     if (active)
  413.     {
  414.     extraDraw = GetMethod(theButton, ICONEXTRADRAW);
  415.     if (extraDraw)
  416.     {
  417.         (* extraDraw) (theButton, (int) ((left + right) / 2), (int) ((top + bottom) / 2) + offset);
  418.     }
  419.     }
  420.  
  421.     return ObjTrue;
  422.  
  423. #endif /* GRAPHICS */
  424. }
  425.  
  426. static ObjPtr SetButtonValuePretend(theButton, theValue)
  427. ObjPtr    theButton, theValue;
  428. {
  429.     FuncTyp    changer;
  430.  
  431.     /* value is ignored, button just gets pressed */
  432.  
  433.     InhibitLogging(true);
  434.     ChangedValue(theButton);
  435.     InhibitLogging(false);
  436.  
  437.     ImInvalid(theButton);
  438.     if (logging) LogControl(theButton);
  439.     return ObjTrue;
  440. }
  441.  
  442. static ObjPtr SetButtonValueReally(theButton, theValue)
  443. ObjPtr    theButton, theValue;
  444. {
  445.     FuncTyp    changer;
  446.  
  447.     if (IsInt(theValue))
  448.     {
  449.     SetVar(theButton, VALUE, theValue);
  450.     }
  451.     else if (IsReal(theValue))
  452.     {
  453.     SetVar(theButton, VALUE, NewInt((int) GetReal(theValue)));
  454.     }
  455.     else
  456.     {
  457.     return ObjFalse;
  458.     }
  459.     InhibitLogging(true);
  460.     ChangedValue(theButton);
  461.     InhibitLogging(false);
  462.  
  463.     ImInvalid(theButton);
  464.     if (logging) LogControl(theButton);
  465.     return ObjTrue;
  466. }
  467.  
  468. #ifdef PROTO
  469. Bool    MakeButtonToggled(ObjPtr theButton, Bool flag)
  470. #else
  471. Bool    MakeButtonToggled(theButton, flag)
  472. ObjPtr theButton;
  473. Bool flag;
  474. #endif
  475. {
  476.     if (flag)
  477.     {
  478.     return SetMethod(theButton, SETVAL, SetButtonValueReally);
  479.     }
  480.     else
  481.     {
  482.     return SetMethod(theButton, SETVAL, SetButtonValuePretend);
  483.     }
  484. }
  485.  
  486. Bool ToggleButtonActivated(ObjPtr theButton)
  487. {
  488.     SetVar(theButton, ACTIVATED, GetPredicate(theButton, ACTIVATED) ? ObjFalse : ObjTrue);
  489.     ImInvalid(theButton);
  490.     return true;
  491. }
  492.  
  493. #ifdef PROTO
  494. Bool ActivateButton(ObjPtr theButton, Bool flag)
  495. #else
  496. Bool ActivateButton(theButton, flag)
  497. ObjPtr theButton;
  498. Bool flag;
  499. #endif
  500. {
  501.     if (flag == GetPredicate(theButton, ACTIVATED))
  502.     {
  503.     return false;
  504.     }
  505.     SetVar(theButton, ACTIVATED, flag ? ObjTrue : ObjFalse);
  506.     ImInvalid(theButton);
  507.     return true;
  508. }
  509.  
  510. /* SetRadioButtonGroupValue: Radio button group SETVAL method */
  511.  
  512. static ObjPtr SetRadioButtonGroupValue(theGroup, theValue)
  513. ObjPtr    theGroup, theValue;
  514. {
  515.     ObjPtr    buttonList;    /* the Radio's list of buttons */
  516.     ThingListPtr    runner;        /* list runner */
  517.     int        buttonNo;    /* counts things as runner runs */
  518.     ObjPtr    oneThing;    /* one thing in the list */
  519.     int        value;        /* value of theValue */
  520.  
  521.     if (IsInt(theValue))
  522.     {
  523.     value = GetInt(theValue);
  524.     }
  525.     else if (IsReal(theValue))
  526.     {
  527.     value = GetReal(theValue);
  528.     }
  529.     else
  530.     {
  531.     return ObjFalse;
  532.     }
  533.     SetVar(theGroup, VALUE, NewInt(value));
  534.  
  535.     /* run down list of buttons and set all but one false. */
  536.     buttonList = GetListVar("SetRadioButtonGroupValue", theGroup, CONTENTS);
  537.     if (!buttonList)
  538.     {
  539.     return ObjFalse;
  540.     }
  541.     
  542.     runner = LISTOF(buttonList);
  543.     buttonNo = 0;
  544.  
  545.     /* find the button in the CONTENTS list */
  546.     while (runner && buttonNo < value)
  547.     {
  548.     runner = runner -> next;
  549.     ++buttonNo;
  550.     }
  551.  
  552.     if (!runner)
  553.     {
  554.     ReportError("SetRadioButtonGroupValue","tried to set to illegal value");
  555.     SetVar(theGroup, VALUE, NewInt(-1));
  556.     ChangedValue(theGroup);
  557.     ImInvalid(theGroup);
  558.     return ObjFalse;
  559.     }
  560.  
  561.     oneThing = runner -> thing;
  562.  
  563.     InhibitLogging(true);
  564.     ButtonPressed(oneThing);
  565.     ChangedValue(theGroup);
  566.     InhibitLogging(false);
  567.  
  568.     if (logging) LogControl(theGroup);
  569.  
  570.     ImInvalid(theGroup);
  571.     return ObjTrue;
  572. }
  573.  
  574. ObjPtr    NewButton(left, right, bottom, top, label)
  575. int    left, right, bottom, top;
  576. char *label;
  577. /*Makes a new panel with bounds left, right, bottom, top, and label label*/
  578. {
  579.     ObjPtr    retVal;
  580.     ObjPtr    labelPtr;
  581.     ObjPtr    hilightPtr;
  582.  
  583.     retVal = NewObject(buttonClass, 0);
  584.     if(retVal)
  585.     {
  586.     labelPtr = NewString(label);
  587.     Set2DIntBounds(retVal, left, right, bottom, top);
  588.     hilightPtr = ObjFalse;
  589.     SetVar(retVal, NAME, labelPtr);
  590.     SetVar(retVal, HIGHLIGHTED, hilightPtr);
  591.     SetVar(retVal, VALUE, NewInt(0));
  592.     SetVar(retVal, ACTIVATED, ObjTrue);
  593.     return retVal;
  594.     }
  595.     else
  596.     {
  597.     return ObjFalse;
  598.     }
  599. }
  600.  
  601. static ObjPtr DrawRadioButtonObj(theButton)
  602. ObjPtr    theButton;
  603. {
  604. #ifdef GRAPHICS
  605.     int left, right, bottom, top;
  606.     Bool    hilight, active;
  607.     Bool    value;
  608.     int        marker;
  609.     char    *label;
  610.  
  611.     if (!Get2DIntBounds(theButton, &left, &right, &bottom, &top))
  612.     {
  613.         return NULLOBJ;
  614.     }
  615.  
  616.     if (IsDrawingRestricted(left, right, bottom, top))
  617.     {
  618.     return ObjFalse;
  619.     }
  620.  
  621.     hilight = GetPredicate(theButton, HIGHLIGHTED);
  622.     active = GetPredicate(theButton, ACTIVATED);
  623.     marker = GetInt(GetIntVar("DrawRadioButtonObj", theButton, MARKERTYPE));
  624.     label = GetString(GetStringVar("DrawRadioButtonObj",theButton, NAME));
  625.     value = GetPredicate(theButton, VALUE);
  626.  
  627.     if (!active)
  628.     BeginTranslucent();
  629.  
  630.     DrawRaisedRect(left, left + (top - bottom), bottom, top, hilight ? UIHIBACKGROUND : UIBACKGROUND);
  631.     if (value)
  632.     {
  633.     switch(marker)
  634.     {
  635.         case MARKERX:
  636.         DrawMarkerX(left+BUTTONDEPTH, left+(top-bottom) - BUTTONDEPTH,
  637.                 bottom + BUTTONDEPTH, top - BUTTONDEPTH);
  638.         break;
  639.         case MARKERCHECK:
  640.         DrawMarkerCheck(left+BUTTONDEPTH, left+(top-bottom)-BUTTONDEPTH,
  641.                 bottom + BUTTONDEPTH, top - BUTTONDEPTH);
  642.         break;
  643.         case MARKERBLOT:
  644.         DrawMarkerBlot(left+BUTTONDEPTH,left+(top-bottom)-BUTTONDEPTH,
  645.                                 bottom + BUTTONDEPTH, top - BUTTONDEPTH);
  646.                 break;
  647.         case MARKERSPLAT:
  648.         DrawMarkerSplat(left+BUTTONDEPTH,left+(top-bottom)-BUTTONDEPTH,
  649.                                 bottom + BUTTONDEPTH, top - BUTTONDEPTH);
  650.                 break;
  651.     }
  652.     }
  653.     if (!active)
  654.     EndTranslucent();
  655.  
  656.     if (label)
  657.     {
  658.     if (active)
  659.         SetUIColor(UITEXT);
  660.     else
  661.         SetUIColor(UIGREYTEXT);
  662.  
  663.     SetUIFont(BUTTONFONT);
  664.         DrawAString(LEFTALIGN, left + (top - bottom) + RADIOSPACER,
  665.                    (top+bottom)/2 + LABELFONTFUDGE - (int) BUTTONFONTSIZE/2,
  666.                    label);
  667.     }
  668. #endif /* GRAPHICS */
  669. }
  670.  
  671. #ifdef PROTO
  672. static Bool TrackMouse(ObjPtr obj, int whichButton)
  673. #else
  674. static Bool TrackMouse(obj, whichButton)
  675. ObjPtr    obj;
  676. int    whichButton;
  677. #endif
  678. {
  679.     int        mX, mY;        /* track mouse coordinates */
  680.     Bool    isDown;        /* return value from Mouse, true if down */
  681.     int        left, right, bottom, top; /* non-array version */
  682.  
  683.     if (!Get2DIntBounds(obj, &left, &right, &bottom, &top))
  684.     {
  685.         return false;
  686.     }
  687.  
  688.     /* the buggy version? */
  689.     while (Mouse(&mX, &mY))
  690.     {
  691.     if (mX < left || mX > right || mY < bottom || mY > top)
  692.     {
  693.         /* mouse outside rectangle */
  694.         if (GetPredicate(obj, HIGHLIGHTED))
  695.         {
  696.         SetVar(obj, HIGHLIGHTED, ObjFalse);/* turn highlight off */
  697.         DrawMe(obj);        /* ..and redraw */
  698.         }
  699.     }
  700.     else
  701.     {
  702.         /* mouse inside rectangle */
  703.         if (!GetPredicate(obj, HIGHLIGHTED))
  704.         {
  705.         SetVar (obj, HIGHLIGHTED, ObjTrue);/* turn highlight on */
  706.         DrawMe(obj);        /* ..and redraw */
  707.         }
  708.     }
  709.     }
  710.     /* always turn highlight off and redraw on exit */
  711.     SetVar(obj, HIGHLIGHTED, ObjFalse);
  712.     ImInvalid(obj);
  713.     /* is this obtuse or what? return true iff mouseup while in rectangle */
  714.     return !(mX < left || mX > right || mY < bottom || mY > top);
  715. }
  716.  
  717. static ObjPtr ButtonPressedButton(theButton)
  718. /* ButtonPressedButton: BUTTONPRESSED Method for vanilla buttons.
  719.     It only toggles the VALUE token of the button. returns true if
  720.     successful, false if not.
  721. */
  722. ObjPtr    theButton;
  723. {
  724.     Bool    value;        /* value of it's VALUE int */
  725.  
  726.     SetValue(theButton, GetPredicate(theButton, VALUE) ? NewInt(0) : NewInt(1));
  727.  
  728.     return ObjTrue;
  729. }
  730.  
  731. static ObjPtr ButtonPressedRadioButton(theButton)
  732. ObjPtr theButton;
  733. {
  734.     ObjPtr    buttonList;    /* the Radio's list of buttons */
  735.     ObjPtr    parent;        /* button's parent */
  736.     ThingListPtr    runner;        /* list runner */
  737.     ObjPtr    oneThing;    /* ont thing in the list */
  738.     int        buttonNo;
  739.  
  740.     /* run down list of buttons and set them all false. */
  741.     parent = GetVar(theButton, PARENT);
  742.     if (!parent)
  743.     {
  744.     ReportError("ButtonPressedRadioButton","Radio button has no PARENT!\n");
  745.     return ObjFalse;
  746.     }
  747.  
  748.     buttonList = GetListVar("ButtonPressedRadioButton", parent, CONTENTS);
  749.     if (!buttonList)
  750.     {
  751.     return ObjFalse;
  752.     }
  753.     else
  754.     {
  755.     runner = LISTOF(buttonList);
  756.     SetVar(parent, VALUE, NewInt(-1));
  757.     buttonNo = 0;
  758.     while (runner)
  759.     {
  760.             ThingPtr oneThing;
  761.  
  762.         oneThing = runner -> thing;
  763.         if (GetPredicate(oneThing, VALUE))
  764.         {
  765.         SetValue(oneThing, NewInt(false));
  766.         /* note there's a quirk here if old button = new button */
  767.         }
  768.         if (runner -> thing == theButton)
  769.         {
  770.         SetVar(parent, VALUE, NewInt(buttonNo));
  771.         }
  772.         ++buttonNo;
  773.         runner = runner -> next;
  774.     }
  775.     }
  776.  
  777.     SetValue(theButton, NewInt(true));
  778.     ChangedValue(parent);
  779.     return ObjTrue;
  780. }
  781.  
  782. /* PressButton: button PRESS method. if mouse down in my rectangle, track
  783.     the mouse and (if up in my rectangle) change the value of the button.
  784.     returns true if mouse down in my rectangle, regardless of whether mouse
  785.     up happened in it.
  786. */
  787. static ObjPtr PressButton(theButton, mouseX, mouseY, flags)
  788. ObjPtr    theButton;
  789. int    mouseX, mouseY;
  790. long    flags;
  791.  
  792. {
  793.  
  794. #ifdef INTERACTIVE
  795.     int left, right, bottom, top;
  796.  
  797.     if (!Get2DIntBounds(theButton, &left, &right, &bottom, &top))
  798.     {
  799.         return ObjFalse;
  800.     }
  801.  
  802.     /* test if mouse in my rectangle */
  803.     if (mouseX < left || mouseX > right ||
  804.     mouseY < bottom || mouseY > top)
  805.     {
  806.     /* mouse out of my rectangle, do nothing, return */
  807.     return ObjFalse;
  808.     }
  809.  
  810.     if (TOOL(flags) == T_HELP)
  811.     {
  812.     ContextHelp(theButton);
  813.     return ObjTrue;
  814.     }
  815.  
  816.     if (!GetPredicate(theButton, ACTIVATED))
  817.     {
  818.     return ObjFalse;
  819.     }
  820.  
  821.     /* have to inhibit Undo saves for radio buttons. */
  822.     if (!inhibitSaveForUndo)
  823.     {
  824.     SaveForUndo(theButton);
  825.     }
  826.  
  827.     MakeMeCurrent(theButton);
  828.  
  829.     if (!TrackMouse(theButton, flags))
  830.     {
  831.     /* mouse up outside of this button, do nothing but draw me */
  832.     ImInvalid(theButton);
  833.     return ObjTrue; /*return true if mousedown in me,regardless of mouseup*/
  834.     }
  835.  
  836.     ButtonPressed(theButton);
  837.  
  838.     /* we hope that logging is handled in the SETVAL method! */
  839.     return ObjTrue;
  840. #endif /* INTERACTIVE */
  841. }
  842.  
  843. ObjPtr    NewRadioButton(left, right, bottom, top, label)
  844. int    left, right, bottom, top;
  845. char    *label;
  846. /*Makes a new panel with bounds left, right, bottom, top, and label label,
  847.     beloging to buttonGroup */
  848. {
  849.     ObjPtr    retVal;
  850.     ObjPtr    labelPtr;
  851.     ObjPtr    hilightPtr;
  852.  
  853.     retVal = NewObject(radioButtonClass, 0);
  854.     if (retVal)
  855.     {
  856.     Set2DIntBounds(retVal, left, right, bottom, top);
  857.     labelPtr = NewString(label);
  858.     SetVar(retVal, NAME, labelPtr);
  859.     hilightPtr = ObjFalse;
  860.     SetVar(retVal, HIGHLIGHTED, hilightPtr);
  861.     SetVar(retVal, VALUE, NewInt(0));
  862.     SetVar(retVal, ACTIVATED, ObjTrue);
  863.     return retVal;
  864.     }
  865.     else
  866.     {
  867.     return ObjFalse;
  868.     }
  869. }
  870.  
  871. /* Makes a new check box with bounds left, right, bottom, top, and label label*/
  872.  
  873. #ifdef PROTO
  874. ObjPtr    NewCheckBox(int left, int right, int bottom, int top, char *label,
  875.             Bool initValue)
  876. #else
  877. ObjPtr    NewCheckBox(left, right, bottom, top, label, initValue)
  878. int    left, right, bottom, top;
  879. Bool    initValue;
  880. char *label;
  881. #endif
  882. {
  883.     ObjPtr    retVal;
  884.     ObjPtr    labelPtr;
  885.     ObjPtr    hilightPtr;
  886.  
  887.     retVal = NewObject(checkBoxClass, 0);
  888.     if (retVal)
  889.     {
  890.     Set2DIntBounds(retVal, left, right, bottom, top);
  891.     labelPtr = NewString(label);
  892.     SetVar(retVal, NAME, labelPtr);
  893.     hilightPtr = ObjFalse;
  894.     SetVar(retVal, HIGHLIGHTED, hilightPtr);
  895.     SetVar(retVal, VALUE, initValue ? NewInt(1) : NewInt(0));
  896.     SetVar(retVal, ACTIVATED, ObjTrue);
  897.     return retVal;
  898.     }
  899.     else
  900.     {
  901.     return ObjFalse;
  902.     }
  903. }
  904.  
  905. static ObjPtr ReshapeRadioButtonGroup(object, ol, or, ob, ot, left, right, bottom, top)
  906. ObjPtr object;
  907. int ol, or, ob, ot;
  908. int left, right, bottom, top;
  909. /*Reshapes object, which used to exist within owner with edges ol, or, ob, ot
  910.   to one which exists within owner with edges left, right, bottom, top.*/
  911. {
  912.     ObjPtr boundsArray;
  913.     ObjPtr stickyInt;
  914.     real bounds[4];
  915.     real oldWidth, oldHeight;    /*Old width and height*/
  916.     Bool sideLocked[4];        /*True iff side is locked*/
  917.     Bool xStretch, yStretch;    /*Stretchiness in x and y*/
  918.     int stickiness;            /*Side stickiness of the object*/
  919.     real oldBounds[4];        /*Old bounds of the object*/
  920.     ObjPtr contents;        /*Contents of the object, if any*/
  921.     real wr, hr;            /*Width and height ratios*/
  922.  
  923.     wr = ((real) (right - left)) / ((real) (or - ol));
  924.     hr = ((real) (top - bottom)) / ((real) (ot - ob));
  925.  
  926.     boundsArray = GetVar(object, BOUNDS);
  927.     if (!boundsArray || !IsArray(boundsArray) || RANK(boundsArray) != 1 ||
  928.         DIMS(boundsArray)[0] != 4)
  929.     {
  930.         return;
  931.     }
  932.     Array2CArray(bounds, boundsArray);
  933.     Array2CArray(oldBounds, boundsArray);
  934.     oldWidth = bounds[1] - bounds[0];
  935.     oldHeight = bounds[3] - bounds[2];
  936.  
  937.     /*Get the object's stickiness*/
  938.     stickyInt = GetVar(object, STICKINESS);
  939.     if (stickyInt && IsInt(stickyInt))
  940.     {
  941.         stickiness = GetInt(stickyInt);
  942.     }
  943.     else
  944.     {
  945.         stickiness = 0;
  946.     }
  947.  
  948.     if ((stickiness & STICKYLEFT) || (stickiness & FLOATINGLEFT))
  949.     {
  950.         if (stickiness & FLOATINGLEFT)
  951.         {
  952.         bounds[0] = (bounds[0] - ol) * wr + left;
  953.         }
  954.         else
  955.         {
  956.         bounds[0] += left - ol;
  957.         }
  958.         if (!((stickiness & STICKYRIGHT) || (stickiness & FLOATINGRIGHT)))
  959.         {
  960.         bounds[1] = bounds[0] + oldWidth;
  961.         }
  962.     }
  963.     if ((stickiness & STICKYRIGHT) || (stickiness & FLOATINGRIGHT))
  964.     {
  965.         if (stickiness & FLOATINGRIGHT)
  966.         {
  967.         bounds[1] = (bounds[1] - ol) * wr + left;
  968.         }
  969.         else
  970.         {
  971.         bounds[1] += right - or;
  972.         }
  973.         if (!((stickiness & STICKYLEFT) || (stickiness & FLOATINGLEFT)))
  974.         {
  975.         bounds[0] = bounds[1] - oldWidth;
  976.         }
  977.     }
  978.  
  979.     if ((stickiness & STICKYBOTTOM) || (stickiness & FLOATINGBOTTOM))
  980.     {
  981.         if (stickiness & FLOATINGBOTTOM)
  982.         {
  983.         bounds[2] = (bounds[2] - ob) * hr + bottom;
  984.         }
  985.         else
  986.         {
  987.         bounds[2] += bottom - ob;
  988.         }
  989.         if (!((stickiness & STICKYTOP) || (stickiness & FLOATINGTOP)))
  990.         {
  991.         bounds[3] = bounds[2] + oldHeight;
  992.         }
  993.     }
  994.     if ((stickiness & STICKYTOP) || (stickiness & FLOATINGTOP))
  995.     {
  996.         if (stickiness & FLOATINGTOP)
  997.         {
  998.         bounds[3] = (bounds[3] - ob) * hr + bottom;
  999.         }
  1000.         else
  1001.         {
  1002.         bounds[3] += top - ot;
  1003.         }
  1004.         if (!((stickiness & STICKYBOTTOM) || (stickiness & FLOATINGBOTTOM)))
  1005.         {
  1006.         bounds[2] = bounds[3] - oldHeight;
  1007.         }
  1008.     }
  1009.  
  1010.     /*We've got a new bounds, put it back*/
  1011.     boundsArray = NewRealArray(1, 4L);
  1012.     CArray2Array(boundsArray, bounds);
  1013.     SetVar(object, BOUNDS, boundsArray);
  1014.  
  1015.     /*If there are some contents to this, do the reshape recursively*/
  1016.     contents = GetVar(object, CONTENTS);
  1017.     if (contents && IsList(contents))
  1018.     {
  1019.         ReshapeList(LISTOF(contents),
  1020.             (int) oldBounds[0], (int) oldBounds[1] ,
  1021.             (int) oldBounds[2], (int) oldBounds[3],
  1022.             (int) bounds[0], (int) bounds[1],
  1023.             (int) bounds[2], (int) bounds[3]);
  1024.     }
  1025. }
  1026.  
  1027.  
  1028. static ObjPtr DrawRadioButtonGroup(theGroup)
  1029. ObjPtr    theGroup;
  1030. {
  1031. #ifdef GRAPHICS
  1032.     ObjPtr    theList;
  1033.  
  1034.     theList = GetListVar("DrawRadioButtonGroup", theGroup, CONTENTS);
  1035.     if (!theList)
  1036.     {
  1037.     return NULLOBJ;
  1038.     }
  1039.  
  1040.     DrawList(theList);
  1041.     return NULLOBJ;
  1042. #endif /* GRAPHICS */
  1043. }
  1044.  
  1045. static ObjPtr PressRadioButtonGroup(theGroup, mX, mY, flags)
  1046. ObjPtr theGroup;
  1047. int mX, mY;
  1048. long flags;
  1049. {
  1050. #ifdef INTERACTIVE
  1051.     int        left, right, bottom, top;
  1052.     ObjPtr    theList;
  1053.     ObjPtr    valuePtr;        /* radio group value ptr */
  1054.     int        oldValue;        /* group's old value */
  1055.     FuncTyp    bpmethod;        /* BUTTONPRESSED method */
  1056.     ObjPtr    pressVal;        /* thing returned by PressList */
  1057.  
  1058.     theList = GetListVar("PressRadioButtonGroup", theGroup, CONTENTS);
  1059.     if (!theList)
  1060.     {
  1061.     return ObjFalse;
  1062.     }
  1063.  
  1064.     if (!Get2DIntBounds(theGroup, &left, &right, &bottom, &top))
  1065.     {
  1066.         return ObjFalse;
  1067.     }
  1068.  
  1069.     valuePtr = GetIntVar("PressRadioButtonGroup", theGroup, VALUE);
  1070.     if (!valuePtr)
  1071.     {
  1072.     return ObjFalse;
  1073.     }
  1074.     oldValue = GetInt(valuePtr);
  1075.  
  1076.     /* test if mouse in my rectangle */
  1077.     if (mX < left || mX > right ||
  1078.     mY < bottom || mY > top)
  1079.     {
  1080.     /* mouse out of my rectangle, do nothing, return */
  1081.     return ObjFalse;
  1082.     }
  1083.  
  1084.     SaveForUndo(theGroup);
  1085.  
  1086.     inhibitSaveForUndo = true;
  1087.     pressVal = PressList(theList, mX, mY, flags);
  1088.     inhibitSaveForUndo = false;
  1089.  
  1090.     if(IsTrue(pressVal))
  1091.     {
  1092.     /* if really changed */
  1093.     if (oldValue != GetInt(GetIntVar("PressRadioButtonGroup",theGroup, VALUE)))
  1094.     {
  1095.         InhibitLogging(true);
  1096.         ButtonPressed(theGroup);
  1097.         InhibitLogging(false);
  1098.     }
  1099.     if (logging) LogControl(theGroup);
  1100.     return ObjTrue;
  1101.     }
  1102.     else
  1103.     {
  1104.     if (TOOL(flags) == T_HELP)
  1105.     {
  1106.         /* it was a help-press in the group bounds (that missed buttons) */
  1107.         ContextHelp(theGroup);
  1108.         return ObjTrue;
  1109.     }
  1110.     else
  1111.     {
  1112.         return ObjFalse;
  1113.     }
  1114.     }
  1115. #endif /* INTERACTIVE */
  1116. }
  1117.  
  1118. ObjPtr    NewRadioButtonGroup(name)
  1119. char *name;
  1120. /* creates an empty radio button group */
  1121. {
  1122.     ObjPtr    retVal;
  1123.  
  1124.     retVal = NewObject(radioGroupClass, 0);
  1125.     if (retVal)
  1126.     {
  1127.     SetVar(retVal, CONTENTS, NewList());
  1128.     SetVar(retVal, VALUE, NewInt(-1));
  1129.     SetVar(retVal, NAME, NewString(name));
  1130.     SetVar(retVal, ACTIVATED, ObjTrue);
  1131.     return retVal;
  1132.     }
  1133.     else
  1134.     {
  1135.     return ObjFalse;
  1136.     }
  1137. }
  1138.  
  1139. void    AddRadioButton(theGroup, theButton)
  1140. ObjPtr    theGroup, theButton;
  1141. /* adds a radio button object to an existing radio button group */
  1142. {
  1143.     ObjPtr    groupBoundsArray;
  1144.     int        bounds[4], groupBounds[4];
  1145.     ObjPtr    theList;
  1146.     int        i;    /* temporary? loop counter */
  1147.  
  1148.     if (!Get2DIntBounds(theButton,&bounds[0],&bounds[1],&bounds[2],&bounds[3]))
  1149.     {
  1150.     return;
  1151.     }
  1152.  
  1153.     theList = GetListVar("AddRadioButton", theGroup, CONTENTS);
  1154.     if(!theList)
  1155.     {
  1156.     return;
  1157.     }
  1158.     groupBoundsArray = GetVar(theGroup, BOUNDS);
  1159.     if(!groupBoundsArray)
  1160.     {
  1161.     /*Try to make bounds. Initial value is bounds of first button*/
  1162.     Set2DIntBounds(theGroup, bounds[0], bounds[1], bounds[2], bounds[3]);
  1163.     }
  1164.     else
  1165.     {
  1166.     Get2DIntBounds(theGroup, &groupBounds[0], &groupBounds[1],
  1167.             &groupBounds[2], &groupBounds[3]);
  1168.     /* if necessary, modify the BOUNDS of the button group to include
  1169.        the new button
  1170.     */
  1171.     groupBounds[0] = bounds[0]<groupBounds[0] ? bounds[0] : groupBounds[0];
  1172.     groupBounds[1] = bounds[1]>groupBounds[1] ? bounds[1] : groupBounds[1];
  1173.     groupBounds[2] = bounds[2]<groupBounds[2] ? bounds[2] : groupBounds[2];
  1174.     groupBounds[3] = bounds[3]>groupBounds[3] ? bounds[3] : groupBounds[3];
  1175.     Set2DIntBounds(theGroup, groupBounds[0], groupBounds[1],
  1176.             groupBounds[2], groupBounds[3]);
  1177.     }
  1178.     PostfixList(theList, theButton);
  1179.     SetVar(theButton, PARENT, theGroup);
  1180.     SetMethod(theButton, BUTTONPRESSED, ButtonPressedRadioButton);
  1181.     SetMethod(theButton, SETVAL, SetButtonValueReally);
  1182.     /*EMP don't log individual buttons, only groups*/
  1183.     SetVar(theButton, INHIBITLOGGING, ObjTrue);
  1184. }
  1185.  
  1186. void    InitButtons()
  1187. /* sets up button stuff */
  1188. {
  1189.     buttonClass = NewObject(controlClass, 0);
  1190.     AddToReferenceList(buttonClass);
  1191.     SetMethod(buttonClass, DRAW, DrawButtonObj);
  1192.     SetMethod(buttonClass, PRESS, PressButton);
  1193.     SetMethod(buttonClass, BUTTONPRESSED, ButtonPressedButton);
  1194.     SetMethod(buttonClass, SETVAL, SetButtonValuePretend);
  1195.     SetVar(buttonClass, TYPESTRING, NewString("button"));
  1196.     SetVar(buttonClass, HELPSTRING, NewString(
  1197. "To press the button, click on it with the left mouse button. If you move the \
  1198. mouse away from the button before releasing, the button will not be pressed."));
  1199.  
  1200.     iconButtonClass = NewObject(buttonClass, 0);
  1201.     AddToReferenceList(iconButtonClass);
  1202.     SetMethod(iconButtonClass, DRAW, DrawIconButtonObj);
  1203.     SetMethod(iconButtonClass, SETVAL, SetButtonValuePretend);
  1204.     SetVar(iconButtonClass, TYPESTRING, NewString("icon button"));
  1205.  
  1206.     iconLabeledButtonClass = NewObject(iconButtonClass, 0);
  1207.     AddToReferenceList(iconLabeledButtonClass);
  1208.     SetMethod(iconLabeledButtonClass, DRAW, DrawIconLabeledButtonObj);
  1209.     SetVar(iconLabeledButtonClass,TYPESTRING,NewString("icon button"));
  1210.  
  1211.     radioGroupClass = NewObject(controlClass, 0);
  1212.     AddToReferenceList(radioGroupClass);
  1213.     SetMethod(radioGroupClass, DRAW, DrawRadioButtonGroup);
  1214.     SetMethod(radioGroupClass, PRESS, PressRadioButtonGroup);
  1215.     SetMethod(radioGroupClass, SETVAL, SetRadioButtonGroupValue);
  1216.     SetMethod(radioGroupClass, RESHAPE, ReshapeRadioButtonGroup);
  1217.     SetVar(radioGroupClass, TYPESTRING, NewString("radio button group"));
  1218.     SetVar(radioGroupClass, HELPSTRING, NewString(
  1219. "A radio button group provides a way to select one choice from among several. \
  1220. Selecting one of the buttons automatically deselects the others in the group."));
  1221.  
  1222.     radioButtonClass = NewObject(buttonClass, 0);
  1223.     AddToReferenceList(radioButtonClass);
  1224.     SetMethod(radioButtonClass, DRAW, DrawRadioButtonObj);
  1225.     SetVar(radioButtonClass, MARKERTYPE, NewInt(MARKERSPLAT));
  1226.     SetVar(radioButtonClass, TYPESTRING, NewString("radio button"));
  1227.  
  1228.     oldRadioButtonClass = NewObject(radioButtonClass, 0);
  1229.     AddToReferenceList(oldRadioButtonClass);
  1230.     SetVar(oldRadioButtonClass, MARKERTYPE, NewInt(MARKERX));
  1231.  
  1232.     checkBoxClass = NewObject(buttonClass, 0);
  1233.     AddToReferenceList(checkBoxClass);
  1234.     SetMethod(checkBoxClass, DRAW, DrawRadioButtonObj);
  1235.     SetMethod(checkBoxClass, SETVAL, SetButtonValueReally);
  1236.     SetVar(checkBoxClass, MARKERTYPE, NewInt(MARKERCHECK));
  1237.     SetVar(checkBoxClass, TYPESTRING, NewString("check box"));
  1238. }
  1239.  
  1240. void KillButtons()
  1241. /* kills button stuff */
  1242. {
  1243.     DeleteThing(checkBoxClass);
  1244.     DeleteThing(radioButtonClass);
  1245.     DeleteThing(radioGroupClass);
  1246.     DeleteThing(iconButtonClass);
  1247.     DeleteThing(buttonClass);
  1248. }
  1249.  
  1250.